<?php

/**
 * Archivo que describe la clase Node
 * @author Alejandro Gama <alejandro.gama@gmail.com>
 * @version 1.0
 * @package core
 * @subpackage config
 * @access private
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
 */
class SecurityCache
{

    static function getResourceInfo( $group, $class )
    {
        $r = false;

        if ( NODES_MEMCACHE_ENABLED ) {
            $r = Config::getMemcached()->get( $group . '#' . $class . '#' . DB_DB );

            if ( !empty( $r ) ) return $r;
        }

        $sql = 'SELECT ' . Config::$helper->escapeIdentifier( 'select' ) . ', ' . Config::$helper->escapeIdentifier( 'sql' ) . ', idNumerico, fin, idCampo FROM security_cache_resources WHERE grupo=' . $group . ' AND nodo=' . $class . ' LIMIT 1';
        $r = MyLink::$default->get_rows( $sql, true )->current();

        if ( $r ) {
            $r[ 2 ] = unserialize( $r[ 2 ] ); //Esto se hace para poder implementar en el futuro objetos con id's de multiples columnas
            $r[ 4 ] = unserialize( $r[ 4 ] ); //Esto se hace para poder implementar en el futuro objetos con id's de multiples columnas

            if ( NODES_MEMCACHE_ENABLED )
                    Config::getMemcached()->set( $group . '#' . $class . '#' . DB_DB,
                        $r, 0, NODES_MEMCACHE_TIME );
        }
        else {

            $small_queries = SMALL_SLOW_QUERIES;

            $conf = Config::getPolicy( $class );


            $recorrido = false;

            if ( !$small_queries ) {
                //con slow_queries quizás no debería acceder a la cache
                //ahora enfrentamos la configuracion del nodo con los privilegios del usuario


                $select = array( );
                // $elwhere = '';
                $selectData = '';
                $numcampos = 0;
                $indiceClase = array( );
                $n = count( $conf[ 'resourceField' ] );
                $rolStr = array( );

                //obtengo los roles con los que puedo acceder a las clases Node definidas para este nodo
                //primero reduzco el número de roles que tengo utilizando solo los atribuidos a esa clase


                $roles = User::getLogged()->getRoles();

                //ACOTO LOS ROLES QUE NECESITO PARA CADA CLASE
                if ( !empty( $roles ) ) {

                    $res = null;
                    $sqlRoles = array( );
                    foreach ( $roles as $t => $ids ) {

                        if ( !empty( $ids ) )
                                $sqlRoles[ ] = 'RolId IN (' . implode( ',', $ids ) . ') AND Rol=' . Config::$helper->safe( $t );
                        else
                                $sqlRoles[ ] = 'RolId=0 AND Rol=' . Config::$helper->safe( $t );
                    }

                    $sqlRoles = 'SELECT DISTINCT Rol,RolId FROM security_privileges WHERE (' . implode( ' OR ',
                                    $sqlRoles ) . ') AND Clase=';

                    foreach ( $conf[ 'classes' ] as $c => $sql ) {
                        //Aqui tendría que quitar el Config::$helper->safe de $c ya que debería ser un número
                        //obtenemos los roles implicados en esa clase
                        //echo 'SELECT DISTINCT Rol,RolId FROM security_privileges WHERE (' . implode(' OR ', $sqlRoles) . ') AND Clase=' . Config::$helper->safe($c);

                        $res = MyLink::$default->get_rows( $sqlRoles . Config::$helper->safe( $c ),
                                        true )->toArray();

                        $rolStr[ $c ] = array( );
                        foreach ( $res as $r )
                                $rolStr[ $c ][ ] = 'RolId=' . (( int ) $r[ 1 ]) . ' AND Rol=' . Config::$helper->safe( $r[ 0 ] ); //roles relacionados con cada uan de las clases de la politica
                    }

                    unset( $res, $sqlRoles );
                }


                $campos = array( );
                $resourceStock = array( );

                //para cada una de las clases y el conjunto de roles con los que podemos acceder a esa clase
                //obtenemos los recursos a los que tenemos acceso
                //recomponemos el where de la consulta para cada una de las clases (el where está partido por los IN USER_RESOURCES)
                //si con una clase no lo coje no pintan nada en las siguientes
                //$resourcestock=array();
                //como tengo el $conf['resourceField'][$i][0]//el tipo $conf['resourceField'][$i][0][1] el id ?????????????????

                foreach ( $rolStr as $c => $rolString ) {

                    //los resources no dependen de $i sino de $c y el conjunto de roles
                    $resources = array( );
                    if ( !empty( $rolString ) ) {

                        $excludeSQL1 = array( );
                        $excludeSQL2 = array( );
                        foreach ( $resourceStock as $t => $ids ) {
                            $excludeSQL1[ ] = '(Recurso<>' . Config::$helper->safe( $t ) . ' OR RecursoId NOT IN (' . implode( ',',
                                            $ids ) . '))';
                            $excludeSQL2[ ] = '(VerticeInicio<>' . Config::$helper->safe( $t ) . ' OR VerticeInicioId NOT IN (' . implode( ',',
                                            $ids ) . '))';
                        }

                        $resources = MyLink::$default->get_rows(
                                        'SELECT DISTINCT Recurso, RecursoId FROM security_privileges WHERE Clase=' . Config::$helper->safe( $c ) . ' AND ( ' . implode( ' OR ',
                                                $rolString ) . ' ) ' . (empty( $excludeSQL1 ) ? '' : ' AND ' . implode( ' AND ',
                                                        $excludeSQL1 )) . ' ORDER BY Recurso,RecursoId',
                                        true
                                )->toArray(); //AND implicita='N'
                    }
                    //ahora tengo que añadir los recursos por debajo de estos
                    //PQ OBTENGO DOS VECES R_DESDEL_1??????????????????????????????
                    //siempre obtengo algún recurso ya que la consulta anterior a esta lo asegura
                    //siempre hay un orden de seleccion de clases y si no se selecciona en la primera, no van valer para la segunda
                    //NOOO, ya que para algunas clases hay un wherea a parte....
                    //Solo las clases que NO tienen un where forman parte del resourcestock
                    //	$resources=array_diff($resources,$resourcestock);
                    $m = count( $resources );

                    //OJO AHORA EL $conf['resourceField'][$i][1] puede estar vacío!!!!!!!!!!!!!!!!!!!!!!!
                    //SI ESTÁ VACIO ME VALEN SOLO LOS RECURSOS QUE TENGAN id=0

                    if ( $m > 0 ) {

                        //AQUI TENGO QUE AÑADIR LOS RECURSOS QUE ESTÁN POR DEBAJO
                        $resourcesSQL = array( );

                        foreach ( $resources as $r ) {
                            if ( !isset( $resourcesSQL[ $r[ 0 ] ] ) )
                                    $resourcesSQL[ $r[ 0 ] ] = array( );

                            $resourcesSQL[ $r[ 0 ] ][ ] = $r[ 1 ];

                            if ( empty( $conf[ 'classes' ][ $c ] ) ) { //los que están en una clase con where no pueden ser descartados en las siguientes
                                if ( !isset( $resourceStock[ $r[ 0 ] ] ) )
                                        $resourceStock[ $r[ 0 ] ] = array( );

                                $resourceStock[ $r[ 0 ] ][ ] = $r[ 1 ];
                            }
                        }

                        $sqls = array( );
                        foreach ( $resourcesSQL as $k => $ids )
                                $sqls[ ] = 'VerticeFin=' . Config::$helper->safe( $k ) . ' AND VerticeFinId IN (' . implode( ',',
                                            $ids ) . ')';

                        //  echo 'SELECT DISTINCT VerticeInicio, VerticeInicioId FROM security_edges WHERE (' . implode(' OR ', $sqls).')'.(empty($excludeSQL2)?'':' AND '.implode(' AND ',$excludeSQL2));
                        $heredados = MyLink::$default->get_rows( 'SELECT DISTINCT VerticeInicio, VerticeInicioId FROM security_edges WHERE (' . implode( ' OR ',
                                                $sqls ) . ')' . (empty( $excludeSQL2 ) ? '' : ' AND ' . implode( ' AND ',
                                                        $excludeSQL2 )), true )->toArray();

                        unset( $excludeSQL1, $excludeSQL2, $sqls );


                        foreach ( $heredados as $h ) {
                            /* NO PUEDE ENCONTRAR NINGUNO SINO HABRÍA CICLOS??
                              $encontrado=false;
                              foreach($resources as $r){
                              if($r[0]==$h[0] && $r[1]==$h[1]){
                              $encontrado=true;
                              break;
                              }
                              }
                              if(!$encontrado){ */
                            $resources[ ] = $h;

                            if ( empty( $conf[ 'classes' ][ $c ] ) ) { //los que están en una clase con where no pueden ser descartados en las siguientes
                                if ( !isset( $resourceStock[ $h[ 0 ] ] ) )
                                        $resourceStock[ $h[ 0 ] ] = array( );

                                $resourceStock[ $h[ 0 ] ][ ] = $h[ 1 ];
                            }

                            //}
                        }

                        unset( $heredados );


                        //group resources by type
                        $resourcesSQL = array( );
                        $totalIds = array( );
                        $totalTypes = 0;

                        foreach ( $resources as $r ) {
                            if ( !isset( $resourcesSQL[ $r[ 0 ] ] ) ) {
                                $resourcesSQL[ $r[ 0 ] ] = array( );
                                $totalTypes++;
                            }

                            $totalIds[ $r[ 1 ] ] = true;
                            if ( !in_array( $r[ 1 ], $resourcesSQL[ $r[ 0 ] ] ) )
                                    $resourcesSQL[ $r[ 0 ] ][ ] = $r[ 1 ];
                        }


                        //we search one intersection
                        $intersection = null;
                        $intersection_types = array( );
                        $min = count( $totalIds ) / $totalTypes;

                        unset( $totalIds, $totalTypes, $resources );

                        //TODOS ES MUY DIFICIL PERO SE PODRIAN HACER GRUPOS DE INTERSECCION
                        foreach ( $resourcesSQL as $k => $ids ) {

                            if ( $intersection === null )
                                    $new_intersection = $ids;
                            else
                                    $new_intersection = array_intersect( $intersection,
                                        $ids );

                            if ( count( $new_intersection ) > $min ) {
                                $intersection = array_values( $new_intersection );
                                $intersection_types[ ] = $k;
                            }
                        }


                        foreach ( $resourcesSQL as $k => $ids ) {

                            if ( $intersection !== null && !empty( $intersection ) )
                                    $ids = array_values( array_diff( $ids,
                                                $intersection ) );



                            if ( empty( $ids ) ) $resourcesSQL[ $k ] = null;

                            else if ( !isset( $ids[ 1 ] ) )
                                    $resourcesSQL[ $k ] = '=' . $ids[ 0 ];
                            else
                                    $resourcesSQL[ $k ] = ' IN (' . implode( ',',
                                                $ids ) . ')'; //puedo asegurar que son numericos por definicion
                        }


                        //var_dump($resourcesSQL);
                        //var_dump($intersection);

                        $sqlrecursos = '';
                        if ( $n == 1 ) {


                            if ( empty( $conf[ 'resourceField' ][ 0 ][ 1 ] ) ) {

                                foreach ( $resourcesSQL as $type => $sql ) {

                                    if ( !empty( $sqlrecursos ) )
                                            $sqlrecursos.=' OR ';

                                    $sqlrecursos.=$conf[ 'resourceField' ][ 0 ][ 0 ] . '=' . Config::$helper->safe( $type );
                                }
                            }
                            else {

                                $sqltypes = '';
                                foreach ( $resourcesSQL as $type => $sql ) {

                                    if ( in_array( $type, $intersection_types ) ) {

                                        if ( !empty( $sqltypes ) )
                                                $sqltypes.=' OR ';

                                        $sqltypes.=$conf[ 'resourceField' ][ 0 ][ 0 ] . '=' . Config::$helper->safe( $type );
                                    }

                                    if ( $sql !== null ) {

                                        if ( !empty( $sqlrecursos ) )
                                                $sqlrecursos.=' OR ';

                                        $sqlrecursos.=$conf[ 'resourceField' ][ 0 ][ 1 ] . $sql . ' AND ' . $conf[ 'resourceField' ][ 0 ][ 0 ] . '=' . Config::$helper->safe( $type );
                                    }
                                }


                                if ( !empty( $intersection ) ) {

                                    if ( !empty( $sqlrecursos ) )
                                            $sqlrecursos.=' OR ';

                                    if ( isset( $intersection[ 1 ] ) )
                                            $sqlrecursos.=$conf[ 'resourceField' ][ 0 ][ 1 ] . ' IN (' . implode( ',',
                                                        $intersection ) . ')';
                                    else
                                            $sqlrecursos.=$conf[ 'resourceField' ][ 0 ][ 1 ] . '=' . $intersection[ 0 ];

                                    if ( isset( $intersection_types[ 1 ] ) )
                                            $string.=' AND (' . $sqltypes . ')';
                                    else $string.=' AND ' . $sqltypes;
                                }

                                unset( $sqltypes );
                            }
                        }
                        else {

                            for ( $i = 0; $i < $n; ++$i ) { //recorremos todos los resourceFields
                                $string = '';

                                if ( empty( $conf[ 'resourceField' ][ $i ][ 1 ] ) ) {

                                    foreach ( $resourcesSQL as $type => $sql ) {

                                        if ( !empty( $string ) )
                                                $string.=' OR ';

                                        $string.=$conf[ 'resourceField' ][ $i ][ 0 ] . '=' . Config::$helper->safe( $type );
                                    }
                                }
                                else {

                                    $sqltypes = '';
                                    foreach ( $resourcesSQL as $type => $sql ) {

                                        if ( in_array( $type,
                                                        $intersection_types ) ) {

                                            if ( !empty( $sqltypes ) )
                                                    $sqltypes.=' OR ';

                                            $sqltypes.=$conf[ 'resourceField' ][ $i ][ 0 ] . '=' . Config::$helper->safe( $type );
                                        }

                                        if ( $sql !== null ) {
                                            if ( !empty( $string ) )
                                                    $string.=' OR ';

                                            $string.=$conf[ 'resourceField' ][ $i ][ 1 ] . $sql . ' AND ' . $conf[ 'resourceField' ][ $i ][ 0 ] . '=' . Config::$helper->safe( $type );
                                        }
                                    }

                                    if ( !empty( $intersection ) ) {
                                        //sort($intersection);

                                        if ( !empty( $string ) )
                                                $string.=' OR ';


                                        if ( isset( $intersection[ 1 ] ) )
                                                $string.=$conf[ 'resourceField' ][ $i ][ 1 ] . ' IN (' . implode( ',',
                                                            $intersection ) . ')';
                                        else
                                                $string.=$conf[ 'resourceField' ][ $i ][ 1 ] . '=' . $intersection[ 0 ];

                                        if ( isset( $intersection_types[ 1 ] ) )
                                                $string.=' AND (' . $sqltypes . ')';
                                        else $string.=' AND ' . $sqltypes;

                                        //  $string.=$conf['resourceField'][$i][1] . ' IN (' . implode(',', $intersection) . ') AND ('.$sqltypes.')';
                                    }
                                }

                                if ( !empty( $sqlrecursos ) )
                                        $sqlrecursos.=' AND ';

                                $sqlrecursos.='(' . $string . ')';
                            }
                        }


                        if ( !empty( $conf[ 'classes' ][ $c ] ) )
                                $sqlrecursos.= ' AND (' . $conf[ 'classes' ][ $c ] . ')';


                        $select[ ] = array( $c, $sqlrecursos );
                        $recorrido = true;
                    }


                    foreach ( $conf[ 'fields' ][ $c ] as $alias => $nombre )
                            if ( !in_array( $alias, $campos ) ) {

                            if ( $alias != $nombre )
                                    $selectData.=', ' . $nombre . ' AS ' . Config::$helper->escapeIdentifier( $alias );
                            else $selectData.=', ' . $nombre;


                            $campos[ ] = $alias;
                        }
                }

                $numclasses = count( $select );
                if ( $numclasses > 0 ) {

                    $select_final = '\'' . $select[ $numclasses - 1 ][ 0 ] . '\'';
                    $elwhere = $select[ $numclasses - 1 ][ 1 ];

                    for ( $i = $numclasses - 2; $i >= 0; $i-- ) {
                        $select_final = 'CASE WHEN ' . $select[ $i ][ 1 ] . ' THEN \'' . $select[ $i ][ 0 ] . '\' ELSE ' . $select_final . ' END';
                        $elwhere.=' OR ' . $select[ $i ][ 1 ];
                    }

                    $select_final.=' AS classname';

                    $selectData = $select_final . $selectData;


                    $elwhere = '(' . $elwhere . ')';
                    if ( !empty( $conf[ 'where' ] ) )
                            $elwhere.=' AND (' . $conf[ 'where' ] . ')';
                }
                else {

                    $selectData = '\'stdClass\' as classname' . $selectData;
                    $elwhere = '0';
                }


                $r = array( $conf[ 'base' ] . ' ' . $selectData, ' FROM ' . $conf[ 'from' ] . ' WHERE  ' . $elwhere,
                    $conf[ 'isNumeric' ], $conf[ 'end' ], $conf[ 'idField' ] );
            } else { //lo bueno de estas es que no se tienen pq borrar cuando se actualizan las tablas de seguridad
                //ahora enfrentamos la configuracion del nodo con los privilegios del usuario
                $select = '';
                $elwhere = '';
                $selectData = '';
                $numcampos = 0;
                $indiceClase = array( );
                $n = count( $conf[ 'resourceField' ] );


                $roles = User::getLogged()->getRoles();
                $sqlRoles = array( );
                foreach ( $roles as $t => $ids )
                        $sqlRoles[ ] = 'RolId IN (' . implode( ',', $ids ) . ') AND Rol=' . Config::$helper->safe( $t );

                $res = MyLink::$default->get_rows(
                                'SELECT DISTINCT Rol,RolId FROM security_privileges WHERE (' . implode( ' OR ',
                                        $sqlRoles ) . ') AND Clase=' . Config::$helper->safe( $c ),
                                true
                        )->toArray();

                foreach ( $conf[ 'classes' ] as $c => $sql ) {

                    if ( $recorrido ) {
                        $select.=', ';
                        $elwhere.=' OR ';
                    }



                    $string = '';
                    if ( empty( $conf[ 'resourceField' ][ $i ][ 0 ] ) ) {
                        for ( $i = 0; $i < $n; ++$i ) {
                            if ( !empty( $string ) ) $string.=' AND ';

                            $string.=$conf[ 'resourceField' ][ $i ][ 0 ] . ' IN (SELECT Recurso FROM security_privileges WHERE (' . implode( ' OR ',
                                            $sqlRoles ) . ') AND Clase=' . Config::$helper->safe( $c ) . ') OR ' . $conf[ 'resourceField' ][ $i ][ 0 ] . ' IN (SELECT VerticeInicio FROM security_edges WHERE VerticeFin IN (SELECT Recurso FROM security_privileges WHERE (' . implode( ' OR ',
                                            $sqlRoles ) . ') AND Clase=' . Config::$helper->safe( $c ) . '))';
                        }
                    }
                    else {
                        for ( $i = 0; $i < $n; ++$i ) {
                            if ( !empty( $string ) ) $string.=' AND ';

                            $string.='(' . $conf[ 'resourceField' ][ $i ][ 0 ] . ',' . $conf[ 'resourceField' ][ $i ][ 1 ] . ') IN (SELECT Recurso,RecursoId FROM security_privileges WHERE (' . implode( ' OR ',
                                            $sqlRoles ) . ') AND Clase=' . Config::$helper->safe( $c ) . ') OR (' . $conf[ 'resourceField' ][ $i ][ 0 ] . ',' . $conf[ 'resourceField' ][ $i ][ 1 ] . ') IN (SELECT VerticeInicio, VerticeInicioId FROM security_edges WHERE (VerticeFin, VerticeFinId) IN (SELECT Recurso, RecursoId FROM security_privileges WHERE (' . implode( ' OR ',
                                            $sqlRoles ) . ') AND Clase=' . Config::$helper->safe( $c ) . '))';
                        }
                    }

                    //si la clase tuviese condiciones propias habría que sumárselas aqui
                    //tanto al select como al where con un AND
                    if ( !empty( $sql ) ) $string.= ' AND (' . $sql . ')';


                    $select[ ] = array( $c, $string );
                    $elwhere.=$string;
                    $recorrido = true;
                }

                $elwhere = '(' . $elwhere . ')';
                if ( !empty( $conf[ 'where' ] ) )
                        $elwhere.=' AND (' . $conf[ 'where' ] . ')';



                $numclasses = count( $select );

                $select_final = '\'' . $select[ $numclasses - 1 ][ 0 ] . '\'';
                for ( $i = $numclasses - 2; $i >= 0; $i-- )
                        $select_final.='CASE WHEN ' . $select[ $i ][ 1 ] . ' THEN \'' . $select[ $i ][ 1 ] . '\' ELSE ' . $select_final . ' END';

                $select_final.=' as classname';





                $r = array( $conf[ 'base' ] . ' ' . $select_final . $conf[ 'selectData' ],
                    'FROM ' . $conf[ 'from' ] . ' WHERE ' . $elwhere, $conf[ 'isNumeric' ],
                    $conf[ 'end' ], $conf[ 'idField' ] );
            }

            self::setResourceInfo( $group, $class, $r );
        }

        return $r;
    }

    private static function setResourceInfo( $group, $class, $data )
    {

        if ( NODES_MEMCACHE_ENABLED ) {
            $result = Config::getMemcached()->replace( $group . '#' . $class . '#' . DB_DB,
                    $data, 0, NODES_MEMCACHE_TIME );

            if ( $result === false )
                    $r = Config::getMemcached()->set( $group . '#' . $class . '#' . DB_DB,
                        $data, 0, NODES_MEMCACHE_TIME );
        }

        $sql = 'INSERT INTO security_cache_resources ( grupo, nodo, ' . Config::$helper->escapeIdentifier( 'select' ) . ', ' . Config::$helper->escapeIdentifier( 'sql' ) . ', idNumerico, fin, idCampo ) VALUES(' .
                $group . ',' . $class . ',' . Config::$helper->safe( $data[ 0 ] ) . ',' . Config::$helper->safe( $data[ 1 ] ) . ',' . Config::$helper->safe( serialize( $data[ 2 ] ) ) . ',' . Config::$helper->safe( $data[ 3 ] ) . ',' . Config::$helper->safe( serialize( $data[ 4 ] ) ) . ')';

        MyLink::$default->execute( $sql );
    }

    static function getBlockInfo( $group, $class )
    {
        $r = false;
        /*
          if (NODES_MEMCACHE_ENABLED) {
          $r = Config::getMemcached()->get($group . '#' . $class . '#' . DB_DB);

          if (!empty($r))
          return $r;
          }
         */
        //  $r = MyLink::$default->get_rows('SELECT clase FROM security_cache_blocks WHERE grupo=' . $group . ' AND nodo=' . $class , true)->getField(0);

        if ( empty( $r ) ) {

            $roles = User::getLogged()->getRoles();


            /*
              //ESTO ES UNA CONSECUENCIA DE TENER SOLO LOS ROLES PRINCIPALES EN EL GRUPO
              if(!empty($roles)){//Añado los roles que heredo de los que tengo puestos
              $sqlinicio='';
              foreach($roles as $t=>$ids){

              if(!empty($sql))
              $sqlinicio.=' OR ';

              $sqlinicio.='VerticeInicioId IN ('.implode(',',$ids).') AND VerticeInicio='.Config::$helper->safe($t);
              }


              $rls=MyLink::$default->get_rows('SELECT VerticeFin, VerticeFinId WHERE '.$sqlinicio,true)->toArray();
              foreach($rls as $r)
              $roles[$r[0]][]=$r[1];
              }
             */

            $classes = Config::getPolicy( $class );

            $r = null;
            foreach ( $classes as $c ) {

                $encontrado = true;
                foreach ( $c[ 'roles' ] as $rols ) {

                    if ( !isset( $roles[ $rols[ 0 ] ] ) || !in_array( $rols[ 1 ],
                                    $roles[ $rols[ 0 ] ] ) ) {
                        $encontrado = false;
                        break;
                    }
                }

                if ( $encontrado ) {
                    $r = $c[ 'class' ];
                    break;
                }
            }

            //if (!empty($r))
            //    SecurityCache::setBlockInfo($group, $class, $r);
        } else if ( NODES_MEMCACHE_ENABLED )
                Config::getMemcached()->set( $group . '#' . $class . '#' . DB_DB,
                    $r, 0, NODES_MEMCACHE_TIME );

        return $r;
    }

    private static function setBlockInfo( $group, $class, $data )
    {
        if ( NODES_MEMCACHE_ENABLED ) {
            $result = Config::getMemcached()->replace( $group . '#' . $class . '#' . DB_DB,
                    $data, 0, NODES_MEMCACHE_TIME );

            if ( $result === false )
                    Config::getMemcached()->set( $group . '#' . $class . '#' . DB_DB,
                        $data, 0, NODES_MEMCACHE_TIME );
        }


        $sql = 'INSERT INTO security_cache_blocks (grupo,clase,nodo) VALUES (' . $group . ',' . Config::$helper->safe( $data,
                        true ) . ',' . $class . ')';
        MyLink::$default->execute( $sql );
    }

    static function clear( $roles, $updategroups = false, $endVertex = null,
            $endVertexId = null )
    {
        //tengo que borrar tb la info de los blocknodes, pero cuando actuamos sólo sobre el arbol de roles!!!!
        //AHORA los roles tienen forma de array con los tipos en los indices y un array de ids en los valores
        //el problema es serializar los roles de forma  univoca
        $rolesStrSQL = array( );

        if ( !empty( $roles ) ) {
            /*
              if($updategroups){ //ESTO ES NECESARIO SI LA RolString sólo tiene los roles base, Ya que cualquiera que tuviera el rol
              //tengo que
              $rls=MyLink::$default->get_rows('SELECT VerticeFin, VerticeFinId WHERE VerticeInicio='.Config::$helper->safe($endVertex).' AND VerticeInicioId='.((int)$endVertexId),true)->toArray();
              foreach($rls as $r)
              $roles[$r[0]][]=$r[1];
              }
             */
            foreach ( $roles as $t => $ids )
                    foreach ( $ids as $id )
                        $rolStrSQL[ ] = Config::$helper->safe_lgr( '|' . $t . '#' . $id . '|',
                            '%', '%' );


            $grupos = MyLink::$default->get_rows( 'SELECT Id FROM security_cache_groups WHERE FullRolStr LIKE ' . implode( ' OR FullRolStr LIKE ',
                                    $rolStrSQL ), true )->toArray();


            if ( !empty( $grupos ) ) {
                if ( NODES_MEMCACHE_ENABLED )
                        foreach ( $grupos as $g )
                            foreach ( Config::$POLICY_TYPE as $n => $type )
                                if ( $type == Node::RESOURCE || $updategroups )
                                    Config::getMemcached()->delete( $g . '#' . $n . '#' . DB_DB ); //tengo que borrar toda la info de los nodos, aqui tb estoy borrando la info de los block

                            $cadenagrupos = implode( ',', $grupos );

                //cuando incorporo roles o vertices no necesito limpiar los grupos ya que siguen siendo subconjuntos válidos
                if ( $updategroups ) {
                    //esta sentencia debería borrar las cachese de resources y bloques
                    $sql = 'UPDATE security_cache_groups SET FullRolStr=\'\' WHERE Id IN (' . $cadenagrupos . ')';
                    MyLink::$default->execute( $sql );

                    $sql = 'DELETE FROM security_cache_resources WHERE grupo IN (' . $cadenagrupos . ')';
                    MyLink::$default->execute( $sql );

                    $sql = 'DELETE FROM security_cache_blocks WHERE grupo IN (' . $cadenagrupos . ')';
                    MyLink::$default->execute( $sql );
                } else {
                    $sql = 'DELETE FROM security_cache_resources WHERE grupo IN (' . $cadenagrupos . ')';
                    MyLink::$default->execute( $sql );
                }
            }
        }
    }

    /*
      static function getGroups($resources){
      $groups=array();
      $tgroups=array();
      $extravaganzas=array();

      foreach($resources as $r){

      $last=strlen($r)-1;
      $i=$last;
      while(is_numeric($r[$i])) $i--;

      if($i!=$last){ //$i es el primer caracter no numÃ©rico
      //primero busco un grupo con el profijo
      $pref=substr($r,0,$i+1);
      $sub=substr($r,$i+1);

      $tienegrupo=false;
      $k=-1;
      $j=0;
      foreach($tgroups as $g){
      if($g['pref']==$pref){
      $k=$j;
      break;
      }
      $j++;
      }

      if($k==-1)
      $tgroups[]=array('pref'=>$pref,'lon'=>$i+2,'subs'=>array($sub),'members'=>1);
      else{
      $tgroups[$k]['subs'][]=$sub;
      $tgroups[$k]['members']++;
      }
      }
      else
      $extravaganzas[]=Config::$helper->safe($r);
      }


      foreach($tgroups as $k=>$g){
      if($g['members']<5){
      foreach($g['subs'] as $s)
      $extravaganzas[]=Config::$helper->safe($g['pref'].$s);
      }
      else
      $groups[]=$g;
      }

      return array($groups,$extravaganzas);
      }
     */
}

?>
